﻿using AE_BEPUPhysics_Addition;
using AE_BEPUPhysics_Addition.Interface;
using BEPUphysics;
using BEPUphysics.BroadPhaseEntries;
using FixMath.NET;
using GameProtocol;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Net;
using TEngine;
using UnityEngine;
using UnityEngine.EventSystems;

namespace GameLogic
{
    [Update]
    public class FightLogicManager : BehaviourSingleton<FightLogicManager>
    {
        FightControler m_FightControler;

        public int ControlShipID
        {
            get { return m_LogicStrategy.GetControlShipID(); }
            set { m_LogicStrategy.SetControlShipID(value); }
        }

        AEPhysicsMgr m_AEPhysicsMgr;
        private int m_LogicFrameCountPersecond = 0;
        private int m_LogicFPS = 0;

        public int LogicFPS
        {
            get => m_LogicFPS;
        }

        private FightLogicStrategy m_LogicStrategy;

        #region 生命周期回调

        public override void Awake()
        {
            base.Awake();
            m_AEPhysicsMgr = new AEPhysicsMgr(new BEPUutilities.Vector3(0, 0, 0));
            m_FightControler = new FightControlerWindows();
            m_FightControler.Awake();
            m_FightControler.OnMoveDirChangedCallback.AddListener(OnMoveDirChanged);
            m_FightControler.OnFocusPositionChangedCallback.AddListener(OnFocusPositionChanged);
            m_FightControler.OnAimPositionCallback.AddListener(OnAimPositionChanged);
            m_FightControler.OnFireChangedCallback.AddListener(OnFireChanged);

            GameEvent.AddEventListener(GameEventType.OnPlayerDisconnected,
                (int conversationID) => { GameModule.UI.ShowUI<FloatingTips>("tips_player_disconnected"); });

            //m_ControlShipID = ship.ShipData.InstanceID;
            var shipObj = GameObject.Find("Ship");
            if (shipObj)
            {
                var sphereCollider = shipObj.GetComponent<AESphereVolumnBaseCollider>();
                m_AEPhysicsMgr.RegisterCollider(sphereCollider);
            }

            var shipObj2 = GameObject.Find("Ship2");
            if (shipObj2)
            {
                var sphereCollider = shipObj2.GetComponent<AESphereVolumnBaseCollider>();
                m_AEPhysicsMgr.RegisterCollider(sphereCollider);
            }
            //Time.timeScale /= 10;
        }

        public bool Raycast(BEPUutilities.Ray ray, Fix64 length, Func<BroadPhaseEntry, bool> filter,
            out RayCastResult result)
        {
            return m_AEPhysicsMgr.RayCast(ray, length, filter, out result);
        }

        float m_LogicFPSTimeCounter = 0;

        public override void Update()
        {
            m_LogicFPSTimeCounter += Time.unscaledDeltaTime;
            if (m_LogicFPSTimeCounter > 1f)
            {
                m_LogicFPSTimeCounter = 0;
                m_LogicFPS = m_LogicFrameCountPersecond;
                m_LogicFrameCountPersecond = 0;
            }

            base.Update();
            m_FightControler.Update();
            if (m_LogicStrategy != null)
                m_LogicStrategy.Update();


            m_AEPhysicsMgr.UpdatePosition();
        }

        #endregion

        #region 回调

        void OnFireChanged(bool fireState)
        {
            if (m_LogicStrategy != null)
                m_LogicStrategy.OnFireChanged(fireState);
        }

        void OnAimPositionChanged(Vector2Int pos)
        {
            if (m_LogicStrategy != null)
                m_LogicStrategy.OnAimPositionChanged(pos);
        }

        void OnFocusPositionChanged(Vector2Int pos)
        {
            if (m_LogicStrategy != null)
                m_LogicStrategy.OnFocusPositionChanged(pos);
        }

        void OnMoveDirChanged(Vector2Int dir)
        {
            if (m_LogicStrategy != null)
                m_LogicStrategy.OnMoveDirChanged(dir);
        }

        #endregion

        #region 开放接口

        public void RegisterCollider(BaseVolumnBaseCollider collider)
        {
            m_AEPhysicsMgr.RegisterCollider(collider);
        }

        public void UnregisterCollider(BaseVolumnBaseCollider collider)
        {
            m_AEPhysicsMgr.UnregisterCollider(collider);
        }

        public BaseCollider GetCollider(int instanceID)
        {
            if (m_AEPhysicsMgr.ColliderMap.ContainsKey(instanceID))
            {
                return m_AEPhysicsMgr.ColliderMap[instanceID];
            }

            return null;
        }

        public void CreateClient(GlobalFunction.ClientType type, string ip = "127.0.0.1")
        {
            FightLogicOnlineStrategy onlineStrategy =
                CreateStrategy(FightLogicStrategy.StrategyType.Online) as FightLogicOnlineStrategy;
            onlineStrategy.CreateClient(type, ip);
        }

        public void SetPlayerControlShipInstanceID(uint playerID, int instanceID)
        {
            var onlineStrategy = m_LogicStrategy as FightLogicOnlineStrategy;
            if (onlineStrategy != null)
                onlineStrategy.SetPlayerControlShipInstanceID(playerID, instanceID);
        }

        public void OnShipDriverChanged()
        {
            var onlineStrategy = m_LogicStrategy as FightLogicOnlineStrategy;
            if (onlineStrategy != null)
                onlineStrategy.OnShipDriverChanged();
        }

        public void DisconnectClient()
        {
            var onlineStrategy = m_LogicStrategy as FightLogicOnlineStrategy;
            if (onlineStrategy != null)
                onlineStrategy.DisconnectClient();
        }

        public void Clear()
        {
            if (m_LogicStrategy == null)
                return;
            m_LogicStrategy.Clear();
            Debug.Log("FightLogicManager:Clear complated");
        }

        #endregion

        #region 私有接口

        FightLogicStrategy CreateStrategy(FightLogicStrategy.StrategyType type)
        {
            FightLogicStrategy strategy = null;
            switch (type)
            {
                case FightLogicStrategy.StrategyType.Offline:
                    strategy = new FightLogicOfflineStrategy();
                    break;
                case FightLogicStrategy.StrategyType.Online:
                    strategy = new FightLogicOnlineStrategy();
                    break;
            }

            if (strategy != null)
            {
                strategy.OnLogicComplete.AddListener(OnLogicComplete);
                strategy.Init();
                m_LogicStrategy = strategy;
            }

            return strategy;
        }

        void OnLogicComplete()
        {
            m_LogicFrameCountPersecond++;
            m_AEPhysicsMgr.PhysicsUpdate(SystemModule.Instance.LogicDelta);
        }

        #endregion
    }
}